On this page

Skip to content

Using Server-Sent-Events (SSE) in .NET

This article mainly introduces how to implement real-time communication in .NET using SSE.

Comparison of SSE and Other Real-time Communication Methods

In JavaScript, there are three common ways to implement real-time communication:

  • Polling: The Client sends requests to the Server periodically to request and receive data. This method often leads to excessive requests and responses, consuming significant resources.

  • Server-Sent-Events (SSE): A unidirectional connection where the Server pushes updated data to the Client. This method has the following advantages: unidirectional connection, reduced server burden, and only one TCP connection, which reduces bandwidth waste.

  • WebSocket: A bidirectional connection established between the Client and the Server, allowing both parties to send data at any time. WebSocket can reduce network traffic and improve efficiency.

SSE JavaScript Implementation

SSE has three default events: open, error, and message. Below is a simple JavaScript example:

SSE Code Example

javascript
const sse = new EventSource('Your API Url');

// Listen to the open event, triggered when the connection is successful
sse.addEventListener('open', function (e) {
  console.log('SSE connection opened');
});

// Listen to the error event, triggered when a connection error occurs
sse.addEventListener('error', function (e) {
  console.log('SSE connection error');
});

// Listen to the message event, triggered when a message is received
sse.addEventListener('message', function (e) {
  console.log('SSE message received', e);

  const data = JSON.parse(e.data);
  const messageElement = document.createElement('div');
  messageElement.textContent = data.message;
  document.body.appendChild(messageElement);
});

// Listen to the custom end event
sse.addEventListener('end', function (e) {
  console.log('SSE custom end', e);

  sse.close();
});

The withCredentials Property

When creating a Server-Sent Events (SSE) object, you can use the withCredentials property to specify whether to send CORS authentication information when making cross-origin requests. This property has no effect in same-origin scenarios.

WARNING

When using SSE with cross-origin requests, the Server-side Header also needs to be configured for CORS accordingly.

javascript
const sse = new EventSource('Your API Url', { withCredentials: true } );

Implementing an SSE Server in .NET

  • The Server sends a message containing an event and data to the Client, and the Client can use the EventSource object to receive these messages. Both event and data are optional, and each message ends with an empty line.
  • The Content-Type returned by the SSE Server is text/event-stream.

Implementation using ASHX (Generic Handler)

ASHX is a feature of ASP.NET Web Forms that can easily handle Web requests. In SSE applications, you can use ASHX to handle SSE requests. Below is a simple ASHX code example:

csharp
public class SseHandler : IHttpHandler {
    public void ProcessRequest (HttpContext context) {
        // Set the response Content-Type to text/event-stream
        context.Response.ContentType = "text/event-stream";
        context.Response.CacheControl = "no-cache";

        // Simulate an SSE event stream, sending one message per second
        int count = 0;
        while (count < 10) {
            count++;
            context.Response.Write("data: " + "{\"message\": \"Hello SSE " + count + "\"}\n\n");
            context.Response.Flush();
            System.Threading.Thread.Sleep(1000);
        }

        // Return a custom end event; the JavaScript example above will Close SSE here
        context.Response.Write("event: end\ndata: {}\n\n");
        context.Response.Flush();
        context.Response.End();
    }

    public bool IsReusable {
        get {
            return false;
        }
    }
}

TIP

Each message ends with an empty line, so the first \n indicates a line break in the message, and the second \n indicates the end of the message.

Implementation using ASP.NET Core Web API

csharp
[ApiController]
[Route("[controller]")]
public class SseController : ControllerBase {
    [HttpGet]
    public async Task GetAsync() {
        // Set the response Content-Type to text/event-stream
        Response.Headers.Add("Content-Type", "text/event-stream;");
        Response.Headers.Add("Cache-Control", "no-cache");

        // Simulate an SSE event stream, sending one message per second
        int count = 0;
        while (count < 10) {
            count++;
            await Response.WriteAsync($"data: " + "{\"message\": \"Hello SSE " + count + "\"}\n\n");
            await Response.Body.FlushAsync();
            await Task.Delay(TimeSpan.FromSeconds(1));
        }

        // Return a custom end event; the JavaScript example above will Close SSE here
        await Response.WriteAsync("event: end\ndata: {}\n\n");
        await Response.Body.FlushAsync();
    }
}

Changelog

  • 2023-03-15 Initial document creation.
  • 2024-02-17 Updated content related to withCredentials.